# 导入所需库
import os
import re
import cv2
import numpy as np
from paddleocr import PaddleOCR
from pdf2image import convert_from_path
import shutil
from PIL import Image
import io
import tempfile
import shutil
from fastapi import APIRouter, UploadFile, File, Form, FastAPI, HTTPException
import asyncio
from concurrent.futures import ThreadPoolExecutor
from functools import partial
from typing import List
# 导入配置文件
import config

router_paddle_ocr = APIRouter(prefix="/paddle_ocr", tags=["paddle_ocr"])

# 获取模型目录路径
def get_model_dirs():
    """获取PaddleOCR模型目录路径，同时支持本地和容器环境"""
    # 获取当前脚本的绝对路径
    current_file = os.path.abspath(__file__)
    # 获取当前脚本所在的目录
    current_dir = os.path.dirname(current_file)
    # 构建模型目录的路径
    models_base_dir = os.path.join(current_dir, "custom_models")
    
    # 构建三个模型子目录的路径
    det_model_dir = os.path.join(models_base_dir, "det")
    rec_model_dir = os.path.join(models_base_dir, "rec")
    cls_model_dir = os.path.join(models_base_dir, "cls")
    
    # 确保目录存在
    os.makedirs(det_model_dir, exist_ok=True)
    os.makedirs(rec_model_dir, exist_ok=True)
    os.makedirs(cls_model_dir, exist_ok=True)
    
    return det_model_dir, rec_model_dir, cls_model_dir

def remove_watermark_basic(image):
    """
    基本的去水印处理 - 使用自适应阈值和形态学操作
    
    参数:
        image: 输入图像（PIL Image对象）
    返回:
        处理后的图像（OpenCV格式）
    """
    # 将PIL图像转换为OpenCV格式
    img = np.array(image)
    img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
    
    # 转换为灰度图
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    
    # 自适应阈值处理，增强文本与背景对比度
    thresh = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, 
                                  cv2.THRESH_BINARY, 11, 2)
    
    # 中值滤波去除噪点
    median = cv2.medianBlur(thresh, 3)
    
    # 形态学操作，进一步去除水印
    kernel = np.ones((1, 1), np.uint8)
    opening = cv2.morphologyEx(median, cv2.MORPH_OPEN, kernel, iterations=1)
    
    # 二值化处理，使文本更清晰
    _, binary = cv2.threshold(opening, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
    
    return binary

def remove_watermark_advanced(image):
    """
    高级去水印处理 - 使用多种滤波和增强技术
    
    参数:
        image: 输入图像（PIL Image对象）
    返回:
        处理后的图像（OpenCV格式）
    """
    # 将PIL图像转换为OpenCV格式
    img = np.array(image)
    img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
    
    # 转换为灰度图
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    
    # 提高对比度
    clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
    enhanced = clahe.apply(gray)
    
    # 高斯模糊减少噪声
    blurred = cv2.GaussianBlur(enhanced, (3, 3), 0)
    
    # 锐化图像，增强文本边缘
    kernel = np.array([[-1, -1, -1],
                       [-1,  9, -1],
                       [-1, -1, -1]])
    sharpened = cv2.filter2D(blurred, -1, kernel)
    
    # 二值化处理
    _, binary = cv2.threshold(sharpened, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
    
    # 形态学操作，进一步清理图像
    kernel = np.ones((2, 2), np.uint8)
    cleaned = cv2.morphologyEx(binary, cv2.MORPH_CLOSE, kernel, iterations=1)
    
    return cleaned

def remove_watermark_color_filter(image):
    """
    基于颜色过滤的去水印处理 - 适用于有明显颜色差异的水印
    
    参数:
        image: 输入图像（PIL Image对象）
    返回:
        处理后的图像（OpenCV格式）
    """
    # 将PIL图像转换为OpenCV格式
    img = np.array(image)
    img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
    
    # 转换为HSV颜色空间，便于颜色过滤
    hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
    
    # 定义要保留的颜色范围（这里假设文本是黑色/深色）
    lower_black = np.array([0, 0, 0])
    upper_black = np.array([180, 255, 100])
    
    # 创建掩码
    mask = cv2.inRange(hsv, lower_black, upper_black)
    
    # 反转掩码以保留文本
    mask = cv2.bitwise_not(mask)
    
    # 应用掩码
    result = cv2.bitwise_and(img, img, mask=mask)
    
    # 转换为灰度图
    gray = cv2.cvtColor(result, cv2.COLOR_BGR2GRAY)
    
    # 二值化处理
    _, binary = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
    
    return binary

async def extract_text_from_pdf_async(pdf_path, temp_output_dir=None, watermark_removal_method=None, lang=None, use_gpu=None)->list[str]:
    """
    使用PaddleOCR从PDF中提取文本内容（异步版本）
    
    参数:
        pdf_path (str): PDF文件路径
        temp_output_dir (str): 临时图像输出目录
        watermark_removal_method (str): 去水印方法，可选 'basic', 'advanced'(高级去水印方法处理), 'color_filter'(基于颜色过滤的去水印方法), 'none'
    返回：
        包含所有页面文本的列表(第一个元素为第一页文本，第二个元素为第二页文本，以此类推)
    """
    # 使用配置文件中的参数，如果未提供则使用默认值
    if temp_output_dir is None:
        temp_output_dir = config.PDF_TEMP_DIR
    if watermark_removal_method is None:
        watermark_removal_method = config.DEFAULT_WATERMARK_REMOVAL
    if lang is None:
        lang = config.OCR_LANG
    if use_gpu is None:
        use_gpu = config.OCR_USE_GPU
    
    # 创建一个线程池执行器，用于运行CPU密集型任务
    loop = asyncio.get_event_loop()
    
    # 创建输出目录(如果不存在)
    os.makedirs(temp_output_dir, exist_ok=True)
    
    # 获取模型目录路径
    det_model_dir, rec_model_dir, cls_model_dir = get_model_dirs()
    
    # 初始化PaddleOCR实例
    # 根据配置决定是否使用角度分类器
    use_angle_cls = getattr(config, 'OCR_USE_ANGLE_CLS', True)  # 默认为True，除非配置中指定为False
    
    # 在极低内存环境下，可以尝试减少PaddleOCR模型的内存使用
    if hasattr(config, 'AVAILABLE_MEM_MB') and config.AVAILABLE_MEM_MB < 300:
        # 极低内存模式下的额外优化
        ocr = PaddleOCR(use_angle_cls=use_angle_cls, lang=lang, use_gpu=use_gpu,
                      det_model_dir=det_model_dir, 
                      rec_model_dir=rec_model_dir, 
                      cls_model_dir=cls_model_dir,
                      # 以下参数用于极低内存环境
                      enable_mkldnn=False,  # 禁用MKL-DNN加速
                      cpu_threads=1)  # 减少CPU线程数
    else:
        ocr = PaddleOCR(use_angle_cls=use_angle_cls, lang=lang, use_gpu=use_gpu, 
                      det_model_dir=det_model_dir, 
                      rec_model_dir=rec_model_dir, 
                      cls_model_dir=cls_model_dir)
    
    # 获取PDF信息，包括页数
    try:
        from pdf2image import pdfinfo_from_path
        pdf_info = pdfinfo_from_path(pdf_path)
        num_pages = pdf_info["Pages"]
        
        # 检查页数，如果页数太多，给出警告并采取预防措施
        if num_pages > 20 and hasattr(config, 'AVAILABLE_MEM_MB') and config.AVAILABLE_MEM_MB < 400:
            print(f"警告: PDF页数较多({num_pages}页)且可用内存较低({config.AVAILABLE_MEM_MB}MB)，将使用最小批处理大小")
            batch_size = 1  # 在大PDF且内存不足时强制使用最小批处理大小
        else:
            batch_size = config.PDF_BATCH_SIZE  # 使用配置文件中的批处理大小
    except Exception as e:
        raise Exception(f"无法获取PDF信息: {str(e)}")
    
    all_text = []
    
    # 定义需要过滤的文本模式
    filter_patterns = [
        r'adm\s*in',  # 匹配 "adm in" 及其变体
        r'\d{11}',    # 匹配11位数字（可能是电话号码水印）
        r'idm\s*ni',  # 其他常见水印模式
        r'dm\s*in',   # 其他常见水印模式
    ]
    
    # 定义一个处理单个页面的函数
    async def process_page(i, image):
        try:
            # 强制垃圾回收，确保每页开始处理时内存处于良好状态
            import gc
            gc.collect()
            
            # 降低图像分辨率（对于极低内存环境）
            if hasattr(config, 'AVAILABLE_MEM_MB') and config.AVAILABLE_MEM_MB < 350:
                # 在极低内存模式下降低图像分辨率
                width, height = image.size
                if width > 1500 or height > 1500:
                    scale_factor = min(1500 / width, 1500 / height)
                    new_width = int(width * scale_factor)
                    new_height = int(height * scale_factor)
                    image = image.resize((new_width, new_height), Image.LANCZOS)
            
            # 根据选择的方法去除水印 - CPU密集型操作，放在线程池中执行
            if watermark_removal_method == 'basic':
                processed_image = await loop.run_in_executor(None, remove_watermark_basic, image)
            elif watermark_removal_method == 'advanced':
                processed_image = await loop.run_in_executor(None, remove_watermark_advanced, image)
            elif watermark_removal_method == 'color_filter':
                processed_image = await loop.run_in_executor(None, remove_watermark_color_filter, image)
            else:  # 'none' 或其他值，不进行预处理
                # 将PIL图像转换为OpenCV格式
                img_array = np.array(image)
                processed_image = await loop.run_in_executor(None, 
                                                           lambda x: cv2.cvtColor(x, cv2.COLOR_RGB2BGR), 
                                                           img_array)
            
            # 临时保存处理后的图像文件
            image_path = os.path.join(temp_output_dir, f"page_{i+1}.jpg")
            # 在极低内存环境下降低JPEG质量
            if hasattr(config, 'AVAILABLE_MEM_MB') and config.AVAILABLE_MEM_MB < 350:
                # 使用较低的图像质量
                cv2_quality = [int(cv2.IMWRITE_JPEG_QUALITY), 80]  # 80%质量，节省内存
                await loop.run_in_executor(None, lambda: cv2.imwrite(image_path, processed_image, cv2_quality))
            else:
                await loop.run_in_executor(None, cv2.imwrite, image_path, processed_image)
            
            # 释放内存
            del processed_image
            del image
            
            # 强制垃圾回收
            gc.collect()
            
            # 使用PaddleOCR识别图像中的文本 - CPU/GPU密集型操作，放在线程池中执行
            result = await loop.run_in_executor(None, ocr.ocr, image_path, True)
            
            # 处理识别结果
            page_text = []
            if result is not None:
                # 处理PaddleOCR 2.8.1版本的返回格式
                # 如果result是一个二维列表(每页一个列表)
                if isinstance(result, list) and len(result) > 0 and isinstance(result[0], list):
                    for line in result[0]:  # 取第一个元素(当前页)
                        if line and len(line) >= 2:
                            # 提取文本内容(通常是第二个元素的第一项)
                            text = line[1][0] if isinstance(line[1], (list, tuple)) else str(line[1])
                            
                            # 过滤无关文本
                            should_filter = False
                            for pattern in filter_patterns:
                                if re.search(pattern, text, re.IGNORECASE):
                                    should_filter = True
                                    break
                            
                            # 如果文本不应被过滤且不是纯数字，则添加到结果中
                            if not should_filter and not (text.strip().isdigit() and len(text.strip()) < 3):
                                # 检查是否已经存在相同或相似的文本
                                if text not in page_text:
                                    page_text.append(text)
                else:  # 兼容其他可能的格式
                    for line in result:
                        if line and len(line) >= 2:
                            text = line[1][0] if isinstance(line[1], (list, tuple)) else str(line[1])
                            
                            # 过滤无关文本
                            should_filter = False
                            for pattern in filter_patterns:
                                if re.search(pattern, text, re.IGNORECASE):
                                    should_filter = True
                                    break
                            
                            # 如果文本不应被过滤且不是纯数字，则添加到结果中
                            if not should_filter and not (text.strip().isdigit() and len(text.strip()) < 3):
                                # 检查是否已经存在相同或相似的文本
                                if text not in page_text:
                                    page_text.append(text)
            
            # 删除临时图像文件
            os.remove(image_path)
            
            # 释放内存
            del result
            
            # 强制垃圾回收
            gc.collect()
            
            return "\n".join(page_text)
        except Exception as e:
            return f"处理第{i+1}页时出错: {str(e)}"
    
    # 分批处理PDF页面，避免内存溢出
    for batch_start in range(0, num_pages, batch_size):
        batch_end = min(batch_start + batch_size, num_pages)
        
        # 强制垃圾回收，确保每批次开始前内存处于良好状态
        import gc
        gc.collect()
        
        # 只转换当前批次的页面，添加低内存模式参数
        try:
            # 转换PDF页面为图像
            options = {}
            # 在低内存环境下降低DPI
            if hasattr(config, 'AVAILABLE_MEM_MB'):
                if config.AVAILABLE_MEM_MB < 300:
                    options['dpi'] = 150  # 极低内存环境使用较低DPI
                elif config.AVAILABLE_MEM_MB < 600:
                    options['dpi'] = 200  # 低内存环境使用中等DPI
            
            with ThreadPoolExecutor() as executor:
                images = await loop.run_in_executor(
                    executor, 
                    lambda: convert_from_path(
                        pdf_path, 
                        first_page=batch_start+1, 
                        last_page=batch_end,
                        **options
                    )
                )
        except Exception as e:
            raise Exception(f"转换PDF页面时出错: {str(e)}")
        
        # 根据配置决定是并发处理还是串行处理页面
        if config.PDF_CONCURRENT_TASKS:
            # 并发处理当前批次的所有页面
            tasks = [process_page(i + batch_start, image) for i, image in enumerate(images)]
            batch_results = await asyncio.gather(*tasks)
        else:
            # 串行处理页面，减少内存使用
            batch_results = []
            for i, image in enumerate(images):
                # 处理每个页面时强制等待1秒，给系统时间释放资源
                if hasattr(config, 'AVAILABLE_MEM_MB') and config.AVAILABLE_MEM_MB < 350:
                    await asyncio.sleep(1)
                result = await process_page(i + batch_start, image)
                batch_results.append(result)
                # 每处理完一页就进行垃圾回收
                gc.collect()
                
        all_text.extend(batch_results)
        
        # 释放内存
        del images
        del batch_results
        
        # 强制垃圾回收
        gc.collect()
        
        # 在低内存环境下，批次之间添加短暂延迟，给系统时间恢复
        if hasattr(config, 'AVAILABLE_MEM_MB') and config.AVAILABLE_MEM_MB < 400:
            await asyncio.sleep(2)
    
    # 清理临时目录
    try:
        if os.path.exists(temp_output_dir):
            shutil.rmtree(temp_output_dir)
    except Exception:
        pass  # 忽略清理错误
    
    # 返回所有页面的文本列表
    return all_text

# 保留原始的同步版本函数，用于兼容性
def extract_text_from_pdf(pdf_path, temp_output_dir='output_files/temp', watermark_removal_method='color_filter', lang="ch", use_gpu=False)->list[str]:
    """
    使用PaddleOCR从PDF中提取文本内容（同步版本）
    
    参数:
        pdf_path (str): PDF文件路径
        temp_output_dir (str): 临时图像输出目录
        watermark_removal_method (str): 去水印方法，可选 'basic', 'advanced'(高级去水印方法处理), 'color_filter'(基于颜色过滤的去水印方法), 'none'
    返回：
        包含所有页面文本的列表(第一个元素为第一页文本，第二个元素为第二页文本，以此类推)
    调用：
    # 示例用法
    pdf_path = "input_files\（第1页-4页合同）天安信通-中国银行_贷款合同.pdf"  # 替换为你的PDF文件路径
    extracted_text = extract_text_from_pdf(pdf_path, watermark_removal_method='advanced',lang="ch",use_gpu=False)
    print(extracted_text)
    
    # 打印提取结果
    for i, text in enumerate(extracted_text):
        print(f"Page {i+1}:\n{text}\n{'='*50}")
    """
    # 创建输出目录(如果不存在)
    os.makedirs(temp_output_dir, exist_ok=True)
    
    # 获取模型目录路径
    det_model_dir, rec_model_dir, cls_model_dir = get_model_dirs()
    
    # 初始化PaddleOCR实例
    # 使用中英文预训练模型，禁用GPU加速，并指定模型保存路径
    ocr = PaddleOCR(use_angle_cls=True, lang=lang, use_gpu=use_gpu, 
                   det_model_dir=det_model_dir, 
                   rec_model_dir=rec_model_dir, 
                   cls_model_dir=cls_model_dir)
    
    # 将PDF转换为图像列表(每页一个图像)
    images = convert_from_path(pdf_path)
    
    all_text = []
    
    # 定义需要过滤的文本模式
    filter_patterns = [
        r'adm\s*in',  # 匹配 "adm in" 及其变体
        r'\d{11}',    # 匹配11位数字（可能是电话号码水印）
        r'idm\s*ni',  # 其他常见水印模式
        r'dm\s*in',   # 其他常见水印模式
    ]
    
    # 遍历每一页图像
    for i, image in enumerate(images):
        # 根据选择的方法去除水印
        if watermark_removal_method == 'basic':
            processed_image = remove_watermark_basic(image)
        elif watermark_removal_method == 'advanced':
            processed_image = remove_watermark_advanced(image)
        elif watermark_removal_method == 'color_filter':
            processed_image = remove_watermark_color_filter(image)
        else:  # 'none' 或其他值，不进行预处理
            # 将PIL图像转换为OpenCV格式
            processed_image = np.array(image)
            processed_image = cv2.cvtColor(processed_image, cv2.COLOR_RGB2BGR)
        
        # 临时保存处理后的图像文件
        image_path = os.path.join(temp_output_dir, f"page_{i+1}.jpg")
        cv2.imwrite(image_path, processed_image)
        
        # 保存原始图像用于对比（可选）
        original_image_path = os.path.join(temp_output_dir, f"original_page_{i+1}.jpg")
        image.save(original_image_path, 'JPEG')
        
        # 使用PaddleOCR识别图像中的文本
        result = ocr.ocr(image_path, cls=True)
        
        # 处理识别结果
        page_text = []
        if result is not None:
            # 处理PaddleOCR 2.8.1版本的返回格式
            # 如果result是一个二维列表(每页一个列表)
            if isinstance(result, list) and len(result) > 0 and isinstance(result[0], list):
                for line in result[0]:  # 取第一个元素(当前页)
                    if line and len(line) >= 2:
                        # 提取文本内容(通常是第二个元素的第一项)
                        text = line[1][0] if isinstance(line[1], (list, tuple)) else str(line[1])
                        
                        # 过滤无关文本
                        should_filter = False
                        for pattern in filter_patterns:
                            if re.search(pattern, text, re.IGNORECASE):
                                should_filter = True
                                break
                        
                        # 如果文本不应被过滤且不是纯数字，则添加到结果中
                        if not should_filter and not (text.strip().isdigit() and len(text.strip()) < 3):
                            # 检查是否已经存在相同或相似的文本
                            if text not in page_text:
                                page_text.append(text)
            else:  # 兼容其他可能的格式
                for line in result:
                    if line and len(line) >= 2:
                        text = line[1][0] if isinstance(line[1], (list, tuple)) else str(line[1])
                        
                        # 过滤无关文本
                        should_filter = False
                        for pattern in filter_patterns:
                            if re.search(pattern, text, re.IGNORECASE):
                                should_filter = True
                                break
                        
                        # 如果文本不应被过滤且不是纯数字，则添加到结果中
                        if not should_filter and not (text.strip().isdigit() and len(text.strip()) < 3):
                            # 检查是否已经存在相同或相似的文本
                            if text not in page_text:
                                page_text.append(text)
        
        # 将当前页文本添加到总结果中
        all_text.append("\n".join(page_text))
        
        # 删除临时图像文件
        os.remove(image_path)
        os.remove(original_image_path)  # 删除原始图像文件
    
    # 删除临时目录
    if os.path.exists(temp_output_dir):
        shutil.rmtree(temp_output_dir)
    
    # 返回所有页面的文本列表
    return all_text

def list_to_txt(lst, file_path, separator='\n', keep_origin=True):
    """
    将列表写入文本文件
    :param lst: 要写入的列表
    :param file_path: 输出的文本文件路径
    :param separator: 列表元素分隔符，默认为换行符
    :param keep_origin: 是否保留原始格式（如保留列表的[]符号）（特点）
    """
    try:
        with open(file_path, 'w', encoding='utf-8') as f:
            if keep_origin:
                # 直接写入列表的字符串表示，保留[]符号
                f.write(str(lst))
            else:
                # 将列表元素用指定分隔符连接后写入文件
                f.write(separator.join(str(item) for item in lst))
        print(f"成功将列表写入 {file_path}")
    except Exception as e:
        print(f"写入文件时出错: {e}")

def txt_to_list(file_path, separator='\n', strip_whitespace=True, keep_origin=True):
    """
    从文本文件读取内容到列表
    :param file_path: 文本文件路径
    :param separator: 分隔符，默认为换行符
    :param strip_whitespace: 是否去除元素首尾空白字符
    :param keep_origin: 是否保留原始格式（如文件内容以[]开头结尾，则直接解析为Python列表）
    :return: 读取到的列表
    """
    try:
        with open(file_path, 'r', encoding='utf-8') as f:
            content = f.read()
            
            if keep_origin and content.strip().startswith('[') and content.strip().endswith(']'):
                # 尝试直接解析为Python列表
                try:
                    import ast
                    lst = ast.literal_eval(content.strip())
                    if not isinstance(lst, list):
                        raise ValueError("解析结果不是列表类型")
                except Exception as e:
                    print(f"以原始格式解析失败: {e}，将使用常规方式解析")
                    keep_origin = False
            
            if not keep_origin:
                if separator == '\n':
                    # 按行分割时直接使用splitlines()更安全
                    lst = content.splitlines()
                else:
                    lst = content.split(separator)
                
                if strip_whitespace:
                    lst = [item.strip() for item in lst]
                
        print(f"成功从 {file_path} 读取到列表")
        return lst
    except Exception as e:
        print(f"读取文件时出错: {e}")
        return []
    
def test_list_to_txt():
    # 使用示例
    my_list = ['第一行内容', '第二行内容', '第三行内容']
    list_to_txt(my_list, 'output.txt')  # 默认每行一个元素
    list_to_txt(my_list, 'output_comma.txt', separator=', ')  # 用逗号分隔
    list_to_txt(my_list, 'output_origin.txt', keep_origin=True)  # 保留原始格式



def test_txt_to_list():
    # 使用示例
    list_from_file = txt_to_list('output.txt')  # 默认按行读取
    print(list_from_file)

    comma_list = txt_to_list('output_comma.txt', separator=', ')  # 按逗号分隔读取
    print(comma_list)
    
    # 测试保留原始格式
    origin_list = txt_to_list('output_origin.txt', keep_origin=True)
    print(f"保留原始格式读取: {origin_list}")
    
    # 读取带有原始格式的示例文件
    try:
        contract_list = txt_to_list('input_files/list4page_contract.txt', keep_origin=True)
        print(f"合同文件读取结果类型: {type(contract_list)}")
        print(f"合同文件读取结果前20个字符: {str(contract_list)[:20]}")
    except Exception as e:
        print(f"读取合同文件时出错: {e}")
        

@router_paddle_ocr.post("/extract_text_from_pdf/")
async def extract_text_endpoint(
    file: UploadFile = File(...),
    watermark_removal_method: str = Form(config.DEFAULT_WATERMARK_REMOVAL),
    lang: str = Form(config.OCR_LANG),
    # use_gpu: bool = Form(False)
):
    # 检查文件类型
    if not file.filename.lower().endswith('.pdf'):
        return {"status": "error", "message": "只支持PDF文件格式"}
    
    # 创建临时目录保存上传的PDF文件
    temp_pdf_path = None
    temp_output_dir = None
    
    try:
        # 保存上传的文件
        with tempfile.NamedTemporaryFile(delete=False, suffix=".pdf") as temp_pdf:
            # 将上传的文件内容写入临时文件
            shutil.copyfileobj(file.file, temp_pdf)
            temp_pdf_path = temp_pdf.name
        
        # 验证PDF文件是否可读
        try:
            from pdf2image import pdfinfo_from_path
            pdf_info = pdfinfo_from_path(temp_pdf_path)
            if not pdf_info:
                return {"status": "error", "message": "无法读取PDF文件信息，文件可能已损坏或受保护"}
        except Exception as pdf_error:
            return {"status": "error", "message": f"PDF文件验证失败: {str(pdf_error)}"}
        
        # 创建临时目录用于处理图像
        temp_output_dir = tempfile.mkdtemp(dir=config.PDF_TEMP_DIR if os.path.exists(config.PDF_TEMP_DIR.split('/')[0]) else None)
        
        # 调用异步版本的extract_text_from_pdf函数处理PDF
        result = await extract_text_from_pdf_async(
            pdf_path=temp_pdf_path, 
            temp_output_dir=temp_output_dir,
            watermark_removal_method=watermark_removal_method,
            lang=lang,
            use_gpu=config.OCR_USE_GPU
        )
        
        return {"status": "success", "text": result}
    
    except Exception as e:
        return {"status": "error", "message": f"处理文件时出错: {str(e)}"}
    
    finally:
        # 确保临时文件被删除
        if temp_pdf_path and os.path.exists(temp_pdf_path):
            os.remove(temp_pdf_path)
        
        # 确保临时目录被删除
        if temp_output_dir and os.path.exists(temp_output_dir):
            shutil.rmtree(temp_output_dir)

# 添加一个新的异步路由，专门用于处理PDF文件
@router_paddle_ocr.post("/extract_text_from_pdf_async/")
async def extract_text_from_pdf_async_endpoint(
    file: UploadFile = File(...),
    watermark_removal_method: str = Form(config.DEFAULT_WATERMARK_REMOVAL),
    lang: str = Form(config.OCR_LANG),
    # use_gpu: bool = Form(False)
):
    # 检查文件类型
    if not file.filename.lower().endswith('.pdf'):
        return {"status": "error", "message": "只支持PDF文件格式"}
    
    # 创建临时目录保存上传的PDF文件
    temp_pdf_path = None
    temp_output_dir = None
    
    try:
        # 保存上传的文件
        with tempfile.NamedTemporaryFile(delete=False, suffix=".pdf") as temp_pdf:
            # 将上传的文件内容写入临时文件
            shutil.copyfileobj(file.file, temp_pdf)
            temp_pdf_path = temp_pdf.name
        
        # 验证PDF文件是否可读
        try:
            from pdf2image import pdfinfo_from_path
            pdf_info = pdfinfo_from_path(temp_pdf_path)
            if not pdf_info:
                return {"status": "error", "message": "无法读取PDF文件信息，文件可能已损坏或受保护"}
        except Exception as pdf_error:
            return {"status": "error", "message": f"PDF文件验证失败: {str(pdf_error)}"}
        
        # 创建临时目录用于处理图像
        temp_output_dir = tempfile.mkdtemp(dir=config.PDF_TEMP_DIR if os.path.exists(config.PDF_TEMP_DIR.split('/')[0]) else None)
        
        # 调用异步版本的extract_text_from_pdf函数处理PDF
        result = await extract_text_from_pdf_async(
            pdf_path=temp_pdf_path, 
            temp_output_dir=temp_output_dir,
            watermark_removal_method=watermark_removal_method,
            lang=lang,
            use_gpu=config.OCR_USE_GPU
        )
        
        return {"status": "success", "text": result}
    
    except Exception as e:
        return {"status": "error", "message": f"处理文件时出错: {str(e)}"}
    
    finally:
        # 确保临时文件被删除
        if temp_pdf_path and os.path.exists(temp_pdf_path):
            os.remove(temp_pdf_path)
        
        # 确保临时目录被删除
        if temp_output_dir and os.path.exists(temp_output_dir):
            shutil.rmtree(temp_output_dir)
        

async def process_image_with_ocr(image_path, watermark_removal_method=None, lang=None, use_gpu=None):
    """
    使用PaddleOCR处理单个图像并提取文本
    
    参数:
        image_path: 图像文件路径
        watermark_removal_method: 去水印方法
        lang: 语言
        use_gpu: 是否使用GPU
    返回:
        提取的文本
    """
    # 使用配置文件中的参数，如果未提供则使用默认值
    if watermark_removal_method is None:
        watermark_removal_method = config.DEFAULT_WATERMARK_REMOVAL
    if lang is None:
        lang = config.OCR_LANG
    if use_gpu is None:
        use_gpu = config.OCR_USE_GPU
        
    # 获取模型目录路径
    det_model_dir, rec_model_dir, cls_model_dir = get_model_dirs()
    
    # 强制垃圾回收，确保处理前内存处于良好状态
    import gc
    gc.collect()
    
    # 根据配置决定是否使用角度分类器
    use_angle_cls = getattr(config, 'OCR_USE_ANGLE_CLS', True)
    
    # 在极低内存环境下，可以尝试减少PaddleOCR模型的内存使用
    if hasattr(config, 'AVAILABLE_MEM_MB') and config.AVAILABLE_MEM_MB < 300:
        # 极低内存模式下的额外优化
        ocr = PaddleOCR(use_angle_cls=use_angle_cls, lang=lang, use_gpu=use_gpu,
                      det_model_dir=det_model_dir, 
                      rec_model_dir=rec_model_dir, 
                      cls_model_dir=cls_model_dir,
                      # 以下参数用于极低内存环境
                      enable_mkldnn=False,  # 禁用MKL-DNN加速
                      cpu_threads=1)  # 减少CPU线程数
    else:
        # 初始化PaddleOCR
        ocr = PaddleOCR(use_angle_cls=use_angle_cls, lang=lang, use_gpu=use_gpu, 
                       det_model_dir=det_model_dir, 
                       rec_model_dir=rec_model_dir, 
                       cls_model_dir=cls_model_dir)
    
    # 读取图像
    try:
        # 检查图像大小
        from PIL import Image
        with Image.open(image_path) as img:
            width, height = img.size
            
            # 如果图像太大且内存不足，先调整大小
            if (width > 2000 or height > 2000) and hasattr(config, 'AVAILABLE_MEM_MB') and config.AVAILABLE_MEM_MB < 500:
                # 计算缩放因子
                scale_factor = min(2000 / width, 2000 / height)
                new_width = int(width * scale_factor)
                new_height = int(height * scale_factor)
                
                # 调整图像大小
                img = img.resize((new_width, new_height), Image.LANCZOS)
                
                # 保存调整后的图像
                temp_resized_path = f"{image_path}_resized.jpg"
                img.save(temp_resized_path, quality=85)
                
                # 使用调整后的图像
                image = cv2.imread(temp_resized_path)
                
                # 处理完后删除临时文件
                os.remove(temp_resized_path)
            else:
                image = cv2.imread(image_path)
                
        if image is None:
            raise ValueError(f"无法读取图像: {image_path}")
            
        # 根据选择的方法去除水印
        if watermark_removal_method == 'basic':
            # 转换为PIL图像再处理
            pil_image = Image.open(image_path)
            processed_image = remove_watermark_basic(pil_image)
        elif watermark_removal_method == 'advanced':
            pil_image = Image.open(image_path)
            processed_image = remove_watermark_advanced(pil_image)
        elif watermark_removal_method == 'color_filter':
            pil_image = Image.open(image_path)
            processed_image = remove_watermark_color_filter(pil_image)
        else:  # 'none' 或其他值，不进行预处理
            processed_image = image
            
        # 临时保存处理后的图像
        temp_image_path = f"{image_path}_processed.jpg"
        
        # 在极低内存环境下降低JPEG质量
        if hasattr(config, 'AVAILABLE_MEM_MB') and config.AVAILABLE_MEM_MB < 350:
            # 使用较低的图像质量
            cv2_quality = [int(cv2.IMWRITE_JPEG_QUALITY), 80]  # 80%质量，节省内存
            cv2.imwrite(temp_image_path, processed_image, cv2_quality)
        else:
            cv2.imwrite(temp_image_path, processed_image)
        
        # 释放不必要的内存
        del processed_image
        if 'pil_image' in locals():
            del pil_image
        gc.collect()
        
        # 使用OCR识别文本
        result = ocr.ocr(temp_image_path, cls=True)
        
        # 删除临时处理图像
        if os.path.exists(temp_image_path):
            os.remove(temp_image_path)
            
        # 处理识别结果
        filter_patterns = [
            r'adm\s*in',  # 匹配 "adm in" 及其变体
            r'\d{11}',    # 匹配11位数字（可能是电话号码水印）
            r'idm\s*ni',  # 其他常见水印模式
            r'dm\s*in',   # 其他常见水印模式
        ]
        
        text_list = []
        if result is not None:
            # 处理PaddleOCR 2.8.1版本的返回格式
            if isinstance(result, list) and len(result) > 0 and isinstance(result[0], list):
                for line in result[0]:  # 取第一个元素(当前页)
                    if line and len(line) >= 2:
                        # 提取文本内容
                        text = line[1][0] if isinstance(line[1], (list, tuple)) else str(line[1])
                        
                        # 过滤无关文本
                        should_filter = False
                        for pattern in filter_patterns:
                            if re.search(pattern, text, re.IGNORECASE):
                                should_filter = True
                                break
                        
                        # 如果文本不应被过滤且不是纯数字，则添加到结果中
                        if not should_filter and not (text.strip().isdigit() and len(text.strip()) < 3):
                            if text not in text_list:
                                text_list.append(text)
            else:  # 兼容其他可能的格式
                for line in result:
                    if line and len(line) >= 2:
                        text = line[1][0] if isinstance(line[1], (list, tuple)) else str(line[1])
                        
                        # 过滤无关文本
                        should_filter = False
                        for pattern in filter_patterns:
                            if re.search(pattern, text, re.IGNORECASE):
                                should_filter = True
                                break
                        
                        if not should_filter and not (text.strip().isdigit() and len(text.strip()) < 3):
                            if text not in text_list:
                                text_list.append(text)
        
        # 释放OCR结果内存
        del result
        gc.collect()
                                
        return "\n".join(text_list)
        
    except Exception as e:
        raise Exception(f"处理图像时出错: {str(e)}")

@router_paddle_ocr.post("/extract_text_from_image/")
async def extract_text_from_image_endpoint(
    file: UploadFile = File(...),
    watermark_removal_method: str = Form(config.DEFAULT_WATERMARK_REMOVAL),
    lang: str = Form(config.OCR_LANG)
):
    """
    从上传的图像文件中提取文本
    """
    # 检查文件类型
    allowed_extensions = ['.jpg', '.jpeg', '.png', '.bmp', '.tiff', '.tif']
    file_ext = os.path.splitext(file.filename.lower())[1]
    
    if file_ext not in allowed_extensions:
        return {"status": "error", "message": f"不支持的文件格式，仅支持: {', '.join(allowed_extensions)}"}
    
    # 创建临时文件保存上传的图像
    temp_image_path = None
    
    try:
        # 保存上传的文件
        with tempfile.NamedTemporaryFile(delete=False, suffix=file_ext) as temp_image:
            # 将上传的文件内容写入临时文件
            shutil.copyfileobj(file.file, temp_image)
            temp_image_path = temp_image.name
        
        # 处理图像并提取文本
        text = await process_image_with_ocr(
            image_path=temp_image_path,
            watermark_removal_method=watermark_removal_method,
            lang=lang,
            use_gpu=config.OCR_USE_GPU
        )
        
        return {"status": "success", "text": text}
    
    except Exception as e:
        return {"status": "error", "message": f"处理图像时出错: {str(e)}"}
    
    finally:
        # 确保临时文件被删除
        if temp_image_path and os.path.exists(temp_image_path):
            os.remove(temp_image_path)

@router_paddle_ocr.post("/extract_text_from_multiple_images/")
async def extract_text_from_multiple_images_endpoint(
    files: List[UploadFile] = File(...),
    watermark_removal_method: str = Form(config.DEFAULT_WATERMARK_REMOVAL),
    lang: str = Form(config.OCR_LANG)
):
    """
    从多个上传的图像文件中提取文本
    """
    # 检查文件类型
    allowed_extensions = ['.jpg', '.jpeg', '.png', '.bmp', '.tiff', '.tif']
    temp_image_paths = []
    
    try:
        # 检查文件数量，如果在低内存环境下文件过多，返回警告
        if len(files) > 5 and hasattr(config, 'AVAILABLE_MEM_MB') and config.AVAILABLE_MEM_MB < 400:
            return {
                "status": "error", 
                "message": f"当前系统内存不足({config.AVAILABLE_MEM_MB}MB)，无法同时处理{len(files)}个文件，请减少文件数量或一次处理一个文件"
            }
            
        results = []
        
        # 保存所有上传的文件
        for file in files:
            file_ext = os.path.splitext(file.filename.lower())[1]
            if file_ext not in allowed_extensions:
                continue  # 跳过不支持的文件格式
                
            with tempfile.NamedTemporaryFile(delete=False, suffix=file_ext) as temp_image:
                shutil.copyfileobj(file.file, temp_image)
                temp_image_paths.append(temp_image.name)
        
        # 处理所有图像
        tasks = []
        for image_path in temp_image_paths:
            task = process_image_with_ocr(
                image_path=image_path,
                watermark_removal_method=watermark_removal_method,
                lang=lang,
                use_gpu=config.OCR_USE_GPU
            )
            tasks.append(task)
        
        # 根据配置决定是并发处理还是串行处理
        if config.PDF_CONCURRENT_TASKS:
            # 等待所有任务完成
            results = await asyncio.gather(*tasks, return_exceptions=True)
        else:
            # 串行处理图像，减少内存使用
            results = []
            for i, task in enumerate(tasks):
                try:
                    # 记录执行进度
                    print(f"处理图像 {i+1}/{len(tasks)}")
                    
                    # 极低内存环境下，每次处理前强制垃圾回收
                    import gc
                    gc.collect()
                    
                    # 添加延迟，给系统一些恢复的时间
                    if hasattr(config, 'AVAILABLE_MEM_MB') and config.AVAILABLE_MEM_MB < 350:
                        await asyncio.sleep(1)
                        
                    result = await task
                    results.append(result)
                except Exception as e:
                    results.append(e)
                    
                # 每处理完一个图像就进行垃圾回收
                gc.collect()
                
                # 极低内存环境下，处理后给系统一些恢复的时间
                if hasattr(config, 'AVAILABLE_MEM_MB') and config.AVAILABLE_MEM_MB < 400:
                    await asyncio.sleep(1)
        
        # 处理结果
        processed_results = []
        for i, result in enumerate(results):
            if isinstance(result, Exception):
                processed_results.append({
                    "filename": files[i].filename if i < len(files) else f"未知文件 {i}",
                    "status": "error",
                    "message": str(result)
                })
            else:
                processed_results.append({
                    "filename": files[i].filename if i < len(files) else f"未知文件 {i}",
                    "status": "success",
                    "text": result
                })
        
        return {"status": "success", "results": processed_results}
    
    except Exception as e:
        return {"status": "error", "message": f"处理图像时出错: {str(e)}"}
    
    finally:
        # 确保所有临时文件被删除
        for path in temp_image_paths:
            if os.path.exists(path):
                os.remove(path)
        
